﻿/********************************************************************
	created:	2011/05/12
	created:	12:5:2011   21:42
	filename: 	D:\My Documents\Visual Studio 2010\Projects\IntranetMessager\ServiceLibrary\Processdures.cs
	file path:	D:\My Documents\Visual Studio 2010\Projects\IntranetMessager\ServiceLibrary
	file base:	Processdures
	file ext:	cs
	author:		
	
	purpose:	各种消息的对应处理方法
*********************************************************************/
using System;
using System.Threading.Tasks;
using CommonLibrary;

namespace ServiceLibrary
{
    internal static class Processdures
    {
        #region Nested type: BroadcastAllOnlineUserDelegate

        private delegate void BroadcastAllOnlineUserDelegate(int loginUserId);

        #endregion

        #region 登录处理

        internal static void SignInProcessdure(byte[] byteMessage,
                                               IClientCallBack senderChannel,
                                               string sessionId)
        {
            SendDataToClient sendToClientHandler = senderChannel.SendBack;
            BroadcastAllOnlineUserDelegate broadcastAllOnlineUserDelegate = BroadcastAllOnlineUserProcessdure;
            var envelope = Functions.DeserializeFromBytes<Protocol.MessageEnvelope>(byteMessage);

            var signinData =
                Functions.DeserializeFromBytes<Protocol.SignIn>(envelope.Signed
                                                                    ? CryptoService.RsaDecrypt(envelope.ByteMessage)
                                                                    : envelope.ByteMessage);

            bool verify = DataManagement.ComparePassword(signinData.MyUid, signinData.MyPassword);

            if (verify)
            {
                verify = ServiceRepository.OnlineUsers.AddNew(signinData.MyUid, senderChannel);
                signinData.MyName = DataManagement.QueryUserName(signinData.MyUid);
            }

            signinData.Result = verify;

            var dataToSend = ServiceFunctions.SealMessageToEnvelope(signinData, signinData.MyUid, false, true);
            sendToClientHandler.BeginInvoke(dataToSend, null, null);
            broadcastAllOnlineUserDelegate.BeginInvoke(signinData.MyUid, null, null);
        }

        #endregion

        #region 注销处理

        internal static void SignOutProcessdure(byte[] byteMessage,
                                                IClientCallBack senderChannel,
                                                string sessionId)
        {
            var envelope = Functions.DeserializeFromBytes<Protocol.MessageEnvelope>(byteMessage);
            BroadcastAllOnlineUserDelegate broadcastAllOnlineUserDelegate = BroadcastAllOnlineUserProcessdure;

            if (envelope == null) return;
            var signoutdata =
                Functions.DeserializeFromBytes<Protocol.SignOut>(envelope.ByteMessage);

            if (signoutdata != null)
                ServiceRepository.OnlineUsers.Remove(signoutdata.MyUid);

            if (signoutdata != null)
                broadcastAllOnlineUserDelegate.BeginInvoke(signoutdata.MyUid, null, null);
        }

        #endregion

        #region 注册处理

        internal static void RegNewUserProcessdure(byte[] byteMessage,
                                                   IClientCallBack senderChannel,
                                                   string sessionId)
        {
            SendDataToClient sendToClientHandler = senderChannel.SendBack;

            var envelope = Functions.DeserializeFromBytes<Protocol.MessageEnvelope>(byteMessage);

            var regData =
                Functions.DeserializeFromBytes<Protocol.RegNewUser>(envelope.ByteMessage);

            int myUid;
            regData.Result = DataManagement.AddNewAccount(regData.MyName,
                                                          regData.MyPassword,
                                                          sessionId, out myUid);
            regData.MyUid = myUid;

            //信封UID为新用户UID，信封RSA签名，不使用DES加密
            byte[] dataToSend = ServiceFunctions.SealMessageToEnvelope(regData, regData.MyUid, false, true);
            sendToClientHandler.BeginInvoke(dataToSend, null, null);
        }

        #endregion

        #region 聊天消息处理

        internal static void TalkingProcessdure(byte[] byteMessage,
                                                IClientCallBack senderChannel,
                                                string sessionId)
        {
            var envelope = Functions.DeserializeFromBytes<Protocol.MessageEnvelope>(byteMessage);

            string userKey, userIv;
            KeyProvider.GetUserKey(envelope.MyUid, out userKey, out userIv);

            var talkingMessage =
                Functions.DeserializeFromBytes<Protocol.TalkingPackage>(
                    CryptoService.DesDecrypt(userKey, userIv, envelope.ByteMessage)
                    );

            if (talkingMessage == null)
                return;

            if (!ServiceRepository.OnlineUsers.IsUserSignIn(talkingMessage.MyUid))
                return;

            talkingMessage.MyName = talkingMessage.ReceiverName;

            byte[] message = ServiceFunctions.SealMessageToEnvelope(talkingMessage,
                                                                    talkingMessage.Receiver, true,
                                                                    true);

            ServiceRepository.OnlineUsers.GetChannel(talkingMessage.Receiver, out senderChannel);

            SendDataToClient sendToClientHandler = senderChannel.SendBack;
            sendToClientHandler.BeginInvoke(message, null, null);
        }

        #endregion

        #region 群发处理

        internal static void BroadcastProcessdure(byte[] byteMessage,
                                                  IClientCallBack senderChannel,
                                                  string sessionId)
        {
            SendDataToClient sendToClientHandler = senderChannel.SendBack;

            var envelope = Functions.DeserializeFromBytes<Protocol.MessageEnvelope>(byteMessage);
            string userKey, userIv;
            KeyProvider.GetUserKey(envelope.MyUid, out userKey, out userIv);
            var broadcast =
                Functions.DeserializeFromBytes<Protocol.BroadcastPackage>(
                    CryptoService.DesDecrypt(userKey, userIv, envelope.ByteMessage));

            Parallel.ForEach
                (broadcast.Receivers,
                 i =>
                     {
                         if (!ServiceRepository.OnlineUsers.IsUserSignIn(broadcast.Receivers[i]))
                         {
                             return;
                         }

                         var talk = new Protocol.TalkingPackage
                                        {
                                            Message = broadcast.Message,
                                            MyName = broadcast.MyName,
                                            MyUid = broadcast.MyUid,
                                            SendTime = broadcast.SendTime,
                                            Receiver = broadcast.Receivers[i]
                                        };

                         byte[] message = ServiceFunctions.SealMessageToEnvelope(talk, talk.Receiver,
                                                                                 true, true);
                         if (message == null) return;
                         ServiceRepository.OnlineUsers.GetChannel(talk.Receiver, out senderChannel);
                         sendToClientHandler.BeginInvoke(message, null, null);
                     });
        }

        #endregion

        #region 查询所有在线用户ID and Name

        internal static void QueryAllOnlineUserProcessdure(byte[] byteMessage,
                                                           IClientCallBack senderChannel,
                                                           string sessionId)
        {
            SendDataToClient sendToClientHandler = senderChannel.SendBack;
            var envelope = Functions.DeserializeFromBytes<Protocol.MessageEnvelope>(byteMessage);
            string userKey, userIv;
            KeyProvider.GetUserKey(envelope.MyUid, out userKey, out userIv);
            var queryPackage =
                Functions.DeserializeFromBytes<Protocol.GetOnlineUsers>(
                    CryptoService.DesDecrypt(userKey, userIv, envelope.ByteMessage));

            queryPackage.UserInfos = ServiceRepository.OnlineUsers.GetAll();
            byte[] message = ServiceFunctions.SealMessageToEnvelope(queryPackage, queryPackage.MyUid,
                                                                    true, true);
            sendToClientHandler.BeginInvoke(message, null, null);
        }

        #endregion

        #region 发布所有在线用户ID and Name

        private static void BroadcastAllOnlineUserProcessdure(int loginUserId)
        {
            var broadcastPackage = new Protocol.GetOnlineUsers();
            IClientCallBack senderChannel;
            SendDataToClient sendToClientHandler;

            broadcastPackage.UserInfos = ServiceRepository.OnlineUsers.GetAll();
            broadcastPackage.SendTime = DateTime.Now;

            Parallel.ForEach
                (broadcastPackage.UserInfos,
                 userInfo =>
                     {
                         if (!ServiceRepository.OnlineUsers.IsUserSignIn(userInfo.UserId))
                             return;

                         if (userInfo.UserId == loginUserId)
                             return;

                         broadcastPackage.MyName = userInfo.UserName;
                         broadcastPackage.MyUid = userInfo.UserId;

                         byte[] message = ServiceFunctions.SealMessageToEnvelope(broadcastPackage,
                                                                                 broadcastPackage.MyUid, true,
                                                                                 false);

                         if (message == null)
                             return;

                         ServiceRepository.OnlineUsers.GetChannel(userInfo.UserId, out senderChannel);
                         sendToClientHandler = senderChannel.SendBack;
                         sendToClientHandler.BeginInvoke(message, null, null);
                     });
        }

        #endregion

        #region 查询其他用户昵称

        internal static void QueryUidByNameProcessdure(byte[] byteMessage,
                                                       IClientCallBack senderChannel,
                                                       string sessionId)
        {
            SendDataToClient sendToClientHandler = senderChannel.SendBack;
            var envelope = Functions.DeserializeFromBytes<Protocol.MessageEnvelope>(byteMessage);
            string userKey, userIv;
            KeyProvider.GetUserKey(envelope.MyUid, out userKey, out userIv);
            var package =
                Functions.DeserializeFromBytes<Protocol.GetUid>(
                    CryptoService.DesDecrypt(userKey, userIv, envelope.ByteMessage));

            package.Uids = DataManagement.QueryUserIds(package.NameToFind);
            byte[] message = ServiceFunctions.SealMessageToEnvelope(package, envelope.MyUid, true, true);
            sendToClientHandler.BeginInvoke(message, null, null);
        }

        #endregion

        #region 查询其他用户ID

        internal static void QueryNameByUidProcessdure(byte[] byteMessage,
                                                       IClientCallBack senderChannel,
                                                       string sessionId)
        {
            SendDataToClient sendToClientHandler = senderChannel.SendBack;
            var envelope = Functions.DeserializeFromBytes<Protocol.MessageEnvelope>(byteMessage);
            string userKey, userIv;
            KeyProvider.GetUserKey(envelope.MyUid, out userKey, out userIv);
            var package =
                Functions.DeserializeFromBytes<Protocol.GetNickName>(
                    CryptoService.DesDecrypt(userKey, userIv, envelope.ByteMessage));

            package.NickName = DataManagement.QueryUserName(package.UidToFind);
            byte[] message = ServiceFunctions.SealMessageToEnvelope(package, envelope.MyUid, true, true);

            sendToClientHandler.BeginInvoke(message, null, null);
        }

        #endregion

        #region DES密钥更新请求

        internal static void DesKeyUpdateProcessdure(byte[] byteMessage,
                                                     IClientCallBack senderChannel,
                                                     string sessionId)
        {
            SendDataToClient sendToClientHandler = senderChannel.SendBack;
            var envelope = Functions.DeserializeFromBytes<Protocol.MessageEnvelope>(byteMessage);

            var package =
                Functions.DeserializeFromBytes<Protocol.DesKeyUpdate>(envelope.ByteMessage);
            package.ServerAnswer = true;

            //信封RSA签名，不使用DES加密
            byte[] dataToSend = ServiceFunctions.SealMessageToEnvelope(package, envelope.MyUid, false, true);
            sendToClientHandler.BeginInvoke(dataToSend, null, null);
        }

        #endregion

        #region DES密钥更新请求确认

        internal static void DesKeyUpdateAckProcessdure(byte[] byteMessage,
                                                        IClientCallBack senderChannel,
                                                        string sessionId)
        {
            SendDataToClient sendToClientHandler = senderChannel.SendBack;
            var envelope = Functions.DeserializeFromBytes<Protocol.MessageEnvelope>(byteMessage);
            var package =
                Functions.DeserializeFromBytes<Protocol.DesKeyUpdateAck>(envelope.ByteMessage);
            package.ServerAnswer = KeyProvider.SetUserKey(envelope.MyUid, package.AckKey,
                                                                              package.AckIv);

            //信封RSA签名，不使用DES加密
            byte[] dataToSend = ServiceFunctions.SealMessageToEnvelope(package, envelope.MyUid, false, true);
            sendToClientHandler.BeginInvoke(dataToSend, null, null);
        }

        #endregion

        #region Nested type: SendDataToClient

        private delegate void SendDataToClient(byte[] message);

        #endregion
    }
}